package com.github.caijh.mall.store.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.inject.Inject;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.caijh.commons.util.Asserts;
import com.github.caijh.commons.util.Collections;
import com.github.caijh.commons.util.DateUtils;
import com.github.caijh.commons.util.Strings;
import com.github.caijh.framework.core.enums.IndexEnum;
import com.github.caijh.framework.core.exception.BizException;
import com.github.caijh.framework.data.redis.Redis;
import com.github.caijh.framework.log.util.LogUtils;
import com.github.caijh.mall.bargain.service.StoreBargainService;
import com.github.caijh.mall.category.model.Category;
import com.github.caijh.mall.category.service.CategoryService;
import com.github.caijh.mall.combination.service.StoreCombinationService;
import com.github.caijh.mall.common.MessageConstants;
import com.github.caijh.mall.common.MyRecord;
import com.github.caijh.mall.common.PageParams;
import com.github.caijh.mall.common.enums.ProductStatusEnum;
import com.github.caijh.mall.common.enums.ProductTypeEnum;
import com.github.caijh.mall.constants.Constants;
import com.github.caijh.mall.exception.CrmebException;
import com.github.caijh.mall.front.request.IndexStoreProductSearchRequest;
import com.github.caijh.mall.marketing.model.StoreCoupon;
import com.github.caijh.mall.marketing.service.StoreCouponService;
import com.github.caijh.mall.pass.service.OnePassService;
import com.github.caijh.mall.seckill.service.StoreSeckillService;
import com.github.caijh.mall.store.convert.ProductConvertMapper;
import com.github.caijh.mall.store.dao.StoreProductDao;
import com.github.caijh.mall.store.model.StoreProduct;
import com.github.caijh.mall.store.model.StoreProductAttr;
import com.github.caijh.mall.store.model.StoreProductAttrResult;
import com.github.caijh.mall.store.model.StoreProductAttrValue;
import com.github.caijh.mall.store.model.StoreProductCoupon;
import com.github.caijh.mall.store.model.StoreProductRelation;
import com.github.caijh.mall.store.request.StoreProductAttrValueRequest;
import com.github.caijh.mall.store.request.StoreProductReqBody;
import com.github.caijh.mall.store.request.StoreProductSearchReqBody;
import com.github.caijh.mall.store.request.StoreProductStockRequest;
import com.github.caijh.mall.store.response.StoreProductAttrValueResponse;
import com.github.caijh.mall.store.response.StoreProductTabsHeader;
import com.github.caijh.mall.store.response.StoreProductVo;
import com.github.caijh.mall.store.service.StoreProductAttrResultService;
import com.github.caijh.mall.store.service.StoreProductAttrService;
import com.github.caijh.mall.store.service.StoreProductAttrValueService;
import com.github.caijh.mall.store.service.StoreProductCouponService;
import com.github.caijh.mall.store.service.StoreProductDescriptionService;
import com.github.caijh.mall.store.service.StoreProductRelationService;
import com.github.caijh.mall.store.service.StoreProductService;
import com.github.caijh.mall.store.utilService.ProductUtils;
import com.github.caijh.mall.system.service.SystemAttachmentService;
import com.github.caijh.mall.system.service.SystemConfigService;
import com.github.caijh.mall.utils.Utils;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class StoreProductServiceImpl extends ServiceImpl<StoreProductDao, StoreProduct>
        implements StoreProductService {

    private static final Logger logger = LogUtils.getLogger(StoreProductServiceImpl.class);
    @Resource
    private StoreProductDao dao;
    @Autowired
    private StoreProductAttrService productAttrService;
    @Autowired
    private StoreProductAttrValueService storeProductAttrValueService;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private StoreProductDescriptionService storeProductDescriptionService;
    @Inject
    private Redis redis;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private StoreProductRelationService storeProductRelationService;
    @Autowired
    private SystemAttachmentService systemAttachmentService;
    @Autowired
    private StoreProductAttrResultService storeProductAttrResultService;
    @Autowired
    private StoreProductCouponService storeProductCouponService;
    @Autowired
    private StoreCouponService storeCouponService;
    @Autowired
    private ProductUtils productUtils;
    @Autowired
    private StoreBargainService storeBargainService;
    @Autowired
    private StoreCombinationService storeCombinationService;
    @Autowired
    private StoreSeckillService storeSeckillService;
    @Autowired
    private OnePassService onePassService;

    @Override
    public List<StoreProduct> page(StoreProductSearchReqBody reqBody, PageParams pageParams, List<Integer> productIdList) {
        PageHelper.startPage(pageParams.getPage(), pageParams.getLimit());
        LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(reqBody.getIsBest() != null, StoreProduct::getIsBest, reqBody.getIsBest());
        lambdaQueryWrapper.eq(reqBody.getIsHot() != null, StoreProduct::getIsHot, reqBody.getIsHot());
        lambdaQueryWrapper.eq(reqBody.getIsNew() != null, StoreProduct::getIsNew, reqBody.getIsNew());
        lambdaQueryWrapper.eq(reqBody.getIsBenefit() != null, StoreProduct::getIsBest, reqBody.getIsBenefit());

        lambdaQueryWrapper.in(Collections.isNotEmpty(productIdList), StoreProduct::getId, productIdList);

        lambdaQueryWrapper.eq(StoreProduct::getIsDel, false)
                          .eq(StoreProduct::getMerId, false)
                          .gt(StoreProduct::getStock, 0)
                          .eq(StoreProduct::getIsShow, true)
                          .orderByDesc(StoreProduct::getSort)
                          .orderByDesc(StoreProduct::getId);
        return dao.selectList(lambdaQueryWrapper);
    }

    @Override
    public IPage<StoreProductVo> page(StoreProductSearchReqBody reqBody, PageParams pageParams) {
        LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper = buildStoreProductQueryWrapper(reqBody);

        Function<StoreProduct, StoreProductVo> convertor = product -> {
            StoreProductVo storeProductVo = new StoreProductVo();
            BeanUtils.copyProperties(product, storeProductVo);

            List<StoreProductAttr> attrs = productAttrService
                    .list(Wrappers.<StoreProductAttr>lambdaQuery().eq(StoreProductAttr::getProductId, product.getId())
                                                                  .eq(StoreProductAttr::getType, ProductTypeEnum.NORMAL
                                                                          .getIndex()));

            storeProductVo.setAttr(attrs);

            List<StoreProductAttrValueResponse> storeProductAttrValueResponse = storeProductAttrValueService
                    .list(Wrappers.<StoreProductAttrValue>lambdaQuery().eq(StoreProductAttrValue::getProductId, product.getId())
                                                                       .eq(StoreProductAttrValue::getType, ProductTypeEnum.NORMAL.getIndex()))
                    .stream()
                    .map(ProductConvertMapper.MAPPER::toStoreProductAttrValueVo).collect(Collectors.toList());

            storeProductVo.setAttrValue(storeProductAttrValueResponse);
            storeProductVo
                    .setContent(storeProductDescriptionService.findStoreProductDescription(product.getId(), ProductTypeEnum.NORMAL.getIndex()));
            List<Category> categories = categoryService.getByIds(Strings.toIntListByComma(product.getCateId()));
            storeProductVo.setCateValues(categories.stream().map(Category::getName).collect(Collectors.joining(",")));

            int collectUserCount = storeProductRelationService
                    .count(Wrappers.<StoreProductRelation>lambdaQuery().eq(StoreProductRelation::getProductId, product.getId())
                                                                       .eq(StoreProductRelation::getType, "collect"));
            storeProductVo.setCollectCount(collectUserCount);
            return storeProductVo;
        };
        return this.page(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(reqBody.getCurrent(), reqBody.getLimit()), lambdaQueryWrapper)
                   .convert(convertor);
    }

    private LambdaQueryWrapper<StoreProduct> buildStoreProductQueryWrapper(StoreProductSearchReqBody reqBody) {
        LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper = Wrappers.lambdaQuery();
        switch (IndexEnum.valueOf(reqBody.getType(), ProductStatusEnum.class)) {
            case ON_SELLING:
                //出售中（已上架）
                lambdaQueryWrapper.eq(StoreProduct::getIsShow, true).eq(StoreProduct::getIsDel, false);
                break;
            case NOT_SELLING:
                //仓库中（未上架）
                lambdaQueryWrapper.eq(StoreProduct::getIsShow, false).eq(StoreProduct::getIsDel, false);
                break;
            case SOLD_OUT:
                //已售罄
                lambdaQueryWrapper.le(StoreProduct::getStock, 0).eq(StoreProduct::getIsDel, false);
                break;
            case STOCK_WARNING:
                //警戒库存
                Integer stock = Integer.parseInt(systemConfigService.getValueByKey(Constants.SystemConfig.STORE_STOCK_WARNING));
                lambdaQueryWrapper.le(StoreProduct::getStock, stock).eq(StoreProduct::getIsDel, false);
                break;
            case DELETED:
                //回收站
                lambdaQueryWrapper.eq(StoreProduct::getIsDel, true);
                break;
            default:
                break;
        }

        setProductKeywordsQuery(reqBody, lambdaQueryWrapper);

        lambdaQueryWrapper.apply(StringUtils.isNotBlank(reqBody.getCateId()), Utils.getFindInSetSql("cate_id", reqBody.getCateId()));
        lambdaQueryWrapper.orderByDesc(StoreProduct::getSort).orderByDesc(StoreProduct::getId);
        return lambdaQueryWrapper;
    }

    private void setProductKeywordsQuery(StoreProductSearchReqBody reqBody, LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper) {
        lambdaQueryWrapper.and(StringUtils.isNotBlank(reqBody.getKeywords()), i -> i
                .or().eq(StoreProduct::getId, reqBody.getKeywords())
                .or().like(StoreProduct::getStoreName, reqBody.getKeywords())
                .or().like(StoreProduct::getStoreInfo, reqBody.getKeywords())
                .or().like(StoreProduct::getKeyword, reqBody.getKeywords())
                .or().like(StoreProduct::getBarCode, reqBody.getKeywords()));
    }

    /**
     * 根据产品属性查询
     *
     * @param storeProduct 产品参数
     * @return 产品结果
     */
    @Override
    public StoreProduct getByEntity(StoreProduct storeProduct) {
        LambdaQueryWrapper<StoreProduct> lqw = new LambdaQueryWrapper<>();
        lqw.setEntity(storeProduct);
        return dao.selectOne(lqw);
    }

    /**
     * 新增产品
     *
     * @param storeProductReqBody 新增产品request对象
     */
    @Transactional
    @Override
    public void save(StoreProductReqBody storeProductReqBody) {
        StoreProduct storeProduct = buildStoreProduct(storeProductReqBody);
        save(storeProduct);

        if (Boolean.TRUE.equals(storeProductReqBody.getSpecType())) { // 多属性
            storeProductReqBody.getAttr().forEach(e -> setProductIdAndAttrValues(e, storeProduct.getId(), ProductTypeEnum.NORMAL.getIndex()));
            boolean attrAddResult = productAttrService.saveOrUpdateBatch(storeProductReqBody.getAttr());
            Asserts.isTrue(attrAddResult, () -> BizException.of(MessageConstants.PRODUCT_ATTR_ADD_ERROR));
        } else { // 单属性
            addDefaultStoreProductAttr(storeProductReqBody, storeProduct);
        }
        if (Collections.isNotEmpty(storeProductReqBody.getAttrValue())) {
            List<StoreProductAttrValue> storeProductAttrValues = storeProductReqBody.getAttrValue().stream()
                                                                                    .filter(e -> e.getAttrValue() != null)
                                                                                    .map(e -> buildProductAttrValue(storeProduct, e))
                                                                                    .collect(Collectors.toList());
            // 保存属性
            if (Collections.isNotEmpty(storeProductAttrValues)) {
                boolean saveOrUpdateResult = storeProductAttrValueService.saveOrUpdateBatch(storeProductAttrValues);
                Asserts.isTrue(saveOrUpdateResult, () -> BizException.of(MessageConstants.PRODUCT_ATTR_VALUE_ADD_ERROR));
                StoreProductAttrResult attrResult = new StoreProductAttrResult(
                        0,
                        storeProduct.getId(),
                        systemAttachmentService.clearPrefix(JSON.toJSONString(storeProductReqBody.getAttrValue())),
                        ((int) DateUtils.currentTimestamp()), Constants.PRODUCT_TYPE_NORMAL);
                storeProductAttrResultService.save(attrResult);
            }
        }

        storeProductDescriptionService.updateStoreProductDescription(storeProduct, storeProductReqBody.getContent());

        storeProductCouponService.updateProductCoupons(storeProduct, storeProductReqBody.getCouponIds());
    }

    private StoreProductAttrValue buildProductAttrValue(StoreProduct storeProduct, StoreProductAttrValueRequest e) {
        StoreProductAttrValue productAttrValue = new StoreProductAttrValue();
        BeanUtils.copyProperties(e, productAttrValue);
        productAttrValue.setProductId(storeProduct.getId());
        String sku = String.join(",", e.getAttrValue().keySet());
        productAttrValue.setSuk(sku);
        productAttrValue.setImage(systemAttachmentService.clearPrefix(productAttrValue.getImage()));
        productAttrValue.setAttrValue(JSON.toJSONString(e.getAttrValue()));
        productAttrValue.setType(ProductTypeEnum.NORMAL.getIndex());
        return productAttrValue;
    }

    private void addDefaultStoreProductAttr(StoreProductReqBody storeProductReqBody, StoreProduct storeProduct) {
        StoreProductAttr productAttr = new StoreProductAttr();
        productAttr.setProductId(storeProduct.getId()).setAttrName("规格").setAttrValues("默认").setType(ProductTypeEnum.NORMAL.getIndex());
        boolean success = productAttrService.save(productAttr);
        Asserts.isTrue(success, () -> BizException.of(MessageConstants.PRODUCT_ATTR_ADD_ERROR));

        StoreProductAttrValue productAttrValue = new StoreProductAttrValue();
        BigDecimal commissionL1 = BigDecimal.ZERO;
        BigDecimal commissionL2 = BigDecimal.ZERO;
        if (Collections.isNotEmpty(storeProductReqBody.getAttrValue())) {
            commissionL1 = null != storeProductReqBody.getAttrValue().get(0).getBrokerage()
                    ? storeProductReqBody.getAttrValue().get(0).getBrokerage() : BigDecimal.ZERO;
            commissionL2 = null != storeProductReqBody.getAttrValue().get(0).getBrokerageTwo()
                    ? storeProductReqBody.getAttrValue().get(0).getBrokerageTwo() : BigDecimal.ZERO;
        }

        productAttrValue.setProductId(storeProduct.getId()).setStock(storeProduct.getStock()).setSuk("默认")
                        .setSales(storeProduct.getSales()).setPrice(storeProduct.getPrice())
                        .setImage(storeProduct.getImage())
                        .setCost(storeProduct.getCost()).setBarCode(storeProduct.getBarCode())
                        .setOtPrice(storeProduct.getOtPrice()).setBrokerage(commissionL1).setBrokerageTwo(commissionL2)
                        .setType(ProductTypeEnum.NORMAL.getIndex());
        boolean saveOrUpdateResult = storeProductAttrValueService.save(productAttrValue);
        Asserts.isTrue(saveOrUpdateResult, () -> BizException.of(MessageConstants.PRODUCT_ATTR_VALUE_ADD_ERROR));
    }

    private StoreProduct buildStoreProduct(StoreProductReqBody storeProductReqBody) {
        StoreProduct storeProduct = new StoreProduct();
        BeanUtils.copyProperties(storeProductReqBody, storeProduct);
        storeProduct.setAddTime(((int) DateUtils.currentTimestamp()));
        storeProduct.setImage(systemAttachmentService.clearPrefix(storeProduct.getImage()));
        storeProduct.setSliderImage(systemAttachmentService.clearPrefix(storeProduct.getSliderImage()));
        productUtils.calcPriceForAttrValues(storeProductReqBody, storeProduct);
        return storeProduct;
    }

    @Transactional
    @Override
    public void update(StoreProductReqBody storeProductReqBody) {
        StoreProduct storeProduct = this.buildStoreProduct(storeProductReqBody);
        dao.updateById(storeProduct);

        // 对attr表做全量更新，删除原有数据保存现有数据
        productAttrService.removeByProductId(storeProduct.getId(), ProductTypeEnum.NORMAL.getIndex());
        storeProductAttrValueService.removeByProductId(storeProduct.getId(), ProductTypeEnum.NORMAL.getIndex());
        if (storeProductReqBody.isMoreSpec()) {
            storeProductReqBody.getAttr().forEach(e -> setProductIdAndAttrValues(e, storeProduct.getId(), Constants.PRODUCT_TYPE_NORMAL));
            productAttrService.saveOrUpdateBatch(storeProductReqBody.getAttr());

            if (Collections.isNotEmpty(storeProductReqBody.getAttrValue())) {
                List<StoreProductAttrValue> storeProductAttrValues = storeProductReqBody.getAttrValue().stream()
                                                                                        .filter(e -> e.getAttrValue() != null)
                                                                                        .map(e -> buildProductAttrValue(storeProduct, e))
                                                                                        .collect(Collectors.toList());
                storeProductAttrValueService.saveOrUpdateBatch(storeProductAttrValues);
                storeProductAttrResultService.updateStoreProductAttrResult(storeProduct, storeProductReqBody.getAttrValue());
            }
        } else {
            StoreProductAttr productAttr = new StoreProductAttr();
            productAttr.setProductId(storeProduct.getId()).setAttrName("规格").setAttrValues("默认").setType(0);
            boolean attrAddResult = productAttrService.save(productAttr);
            Asserts.isTrue(attrAddResult, () -> BizException.of(MessageConstants.PRODUCT_ATTR_ADD_ERROR));

            Asserts.isTrue(Collections.isNotEmpty(storeProductReqBody.getAttrValue()), () -> new CrmebException("attrValue不能为空"));
            StoreProductAttrValue singleAttrValue = buildProductAttrValue(storeProduct, storeProductReqBody.getAttrValue().get(0));
            storeProductAttrValueService.save(singleAttrValue);
        }

        storeProductDescriptionService.updateStoreProductDescription(storeProduct, storeProductReqBody.getContent());

        storeProductCouponService.updateProductCoupons(storeProduct, storeProductReqBody.getCouponIds());
    }

    private void setProductIdAndAttrValues(StoreProductAttr storeProductAttr, Integer productId, int productTypeNormal) {
        storeProductAttr.setProductId(productId);
        storeProductAttr.setAttrValues(StringUtils.strip(storeProductAttr.getAttrValues().replace("\"", ""), "[]"));
        storeProductAttr.setType(productTypeNormal);
    }

    /**
     * 商品详情
     *
     * @param id 商品id
     * @return 详情数据
     */
    @Override
    public StoreProductVo getByProductId(int id) {
        StoreProduct storeProduct = this.getById(id);
        Asserts.notNull(storeProduct, () -> BizException.of(MessageConstants.PRODUCT_NOT_FOUND));

        StoreProductVo storeProductVo = ProductConvertMapper.MAPPER.toStoreProductVo(storeProduct);

        storeProductVo.setAttr(productAttrService.getProductAttrs(id, ProductTypeEnum.NORMAL));

        storeProductVo.setActivityH5(productUtils.getProductCurrentActivity(storeProduct));
        List<StoreProductAttrValue> storeProductAttrValues = storeProductAttrValueService.getProductAttrValues(id, ProductTypeEnum.NORMAL);

        // 根据attrValue生成前端所需的数据
        List<Map<String, Object>> attrValues = new ArrayList<>();

        if (Boolean.TRUE.equals(storeProduct.getSpecType())) {
            StoreProductAttrResult sparPram = new StoreProductAttrResult();
            sparPram.setProductId(storeProduct.getId()).setType(Constants.PRODUCT_TYPE_NORMAL);
            List<StoreProductAttrResult> attrResults = storeProductAttrResultService.getByEntity(sparPram);
            if (Collections.isEmpty(attrResults)) {
                throw new CrmebException("未找到对应属性值");
            }
            StoreProductAttrResult attrResult = attrResults.get(0);
            //PC 端生成skuAttrInfo
            List<StoreProductAttrValueRequest> storeProductAttrValueRequests = JSON.parseArray(attrResult.getResult(), StoreProductAttrValueRequest.class);
            if (null != storeProductAttrValueRequests) {
                for (int i = 0; i < storeProductAttrValueRequests.size(); i++) {
                    Map<String, Object> attrValue = new HashMap<>();
                    String currentSku = storeProductAttrValues.get(i).getSuk();
                    List<StoreProductAttrValue> hasCurrentSku =
                            storeProductAttrValues.stream().filter(e -> e.getSuk().equals(currentSku)).collect(Collectors.toList());
                    StoreProductAttrValue currentAttrValue = hasCurrentSku.get(0);
                    attrValue.put("id", hasCurrentSku.size() > 0 ? hasCurrentSku.get(0).getId() : 0);
                    attrValue.put("image", currentAttrValue.getImage());
                    attrValue.put("cost", currentAttrValue.getCost());
                    attrValue.put("price", currentAttrValue.getPrice());
                    attrValue.put("otPrice", currentAttrValue.getOtPrice());
                    attrValue.put("stock", currentAttrValue.getStock());
                    attrValue.put("barCode", currentAttrValue.getBarCode());
                    attrValue.put("weight", currentAttrValue.getWeight());
                    attrValue.put("volume", currentAttrValue.getVolume());
                    attrValue.put("suk", currentSku);
                    attrValue.put("attrValue", JSON.parseObject(storeProductAttrValues.get(i).getAttrValue(), Feature.OrderedField));
                    attrValue.put("brokerage", currentAttrValue.getBrokerage());
                    attrValue.put("brokerage_two", currentAttrValue.getBrokerageTwo());
                    String[] skus = currentSku.split(",");
                    for (int k = 0; k < skus.length; k++) {
                        attrValue.put("value" + k, skus[k]);
                    }
                    attrValues.add(attrValue);
                }
            }
        }

        // H5 端用于生成skuList
        List<StoreProductAttrValueResponse> skuList = storeProductAttrValues.stream().map(ProductConvertMapper.MAPPER::toStoreProductAttrValueVo)
                                                                            .collect(Collectors.toList());

        storeProductVo.setAttrValues(attrValues);
        storeProductVo.setAttrValue(skuList);
        storeProductVo.setContent(storeProductDescriptionService.findStoreProductDescription(storeProduct.getId(), ProductTypeEnum.NORMAL.getIndex()));
        List<StoreProductCoupon> storeProductCoupons = storeProductCouponService.listByProductId(storeProduct.getId());
        if (Collections.isNotEmpty(storeProductCoupons)) {
            List<Integer> ids = storeProductCoupons.stream().map(StoreProductCoupon::getIssueCouponId).collect(Collectors.toList());
            List<StoreCoupon> shipCoupons = storeCouponService.getByIds(ids);
            storeProductVo.setCoupons(shipCoupons);
            storeProductVo.setCouponIds(ids);
        }
        return storeProductVo;
    }

    /**
     * 产品列表
     *
     * @param request    商品查询参数
     * @param pageParams 分页参数
     * @return 商品查询结果
     */
    @Override
    public List<StoreProduct> page(IndexStoreProductSearchRequest request, PageParams pageParams) {
        PageHelper.startPage(pageParams.getPage(), pageParams.getLimit());
        LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper = Wrappers.lambdaQuery();
        if (request.getIsBest() != null) {
            lambdaQueryWrapper.eq(StoreProduct::getIsBest, request.getIsBest());
        }

        if (request.getIsHot() != null) {
            lambdaQueryWrapper.eq(StoreProduct::getIsHot, request.getIsHot());
        }

        if (request.getIsNew() != null) {
            lambdaQueryWrapper.eq(StoreProduct::getIsNew, request.getIsNew());
        }

        if (request.getIsBenefit() != null) {
            lambdaQueryWrapper.eq(StoreProduct::getIsBenefit, request.getIsBenefit());
        }

        lambdaQueryWrapper.eq(StoreProduct::getIsDel, false)
                          .eq(StoreProduct::getMerId, false)
                          .gt(StoreProduct::getStock, 0)
                          .eq(StoreProduct::getIsShow, true)
                          .orderByDesc(StoreProduct::getSort);
        if (!StringUtils.isBlank(request.getPriceOrder())) {
            if (request.getPriceOrder().equals(Constants.SORT_DESC)) {
                lambdaQueryWrapper.orderByDesc(StoreProduct::getPrice);
            } else {
                lambdaQueryWrapper.orderByAsc(StoreProduct::getPrice);
            }
        }

        if (!StringUtils.isBlank(request.getSalesOrder())) {
            if (request.getSalesOrder().equals(Constants.SORT_DESC)) {
                lambdaQueryWrapper.orderByDesc(StoreProduct::getSales);
            } else {
                lambdaQueryWrapper.orderByAsc(StoreProduct::getSales);
            }
        }
        if (null != request.getCateId() && request.getCateId().size() > 0) {
            lambdaQueryWrapper.apply(Utils.getFindInSetSql("cate_id", request.getCateId()));
        }

        if (StringUtils.isNotBlank(request.getKeywords())) {
            if (Strings.isInt(request.getKeywords())) {
                Integer productId = Integer.valueOf(request.getKeywords());
                lambdaQueryWrapper.like(StoreProduct::getId, productId);
            } else {
                lambdaQueryWrapper
                        .like(StoreProduct::getStoreName, request.getKeywords())
                        .or().like(StoreProduct::getStoreInfo, request.getKeywords())
                        .or().like(StoreProduct::getBarCode, request.getKeywords());
            }
        }

        lambdaQueryWrapper.orderByDesc(StoreProduct::getId);
        return dao.selectList(lambdaQueryWrapper);
    }

    /**
     * 根据商品tabs获取对应类型的产品数量
     *
     * @return {@code List<StoreProductTabsHeader>}
     */
    @Override
    public List<StoreProductTabsHeader> getTabsHeader() {
        List<StoreProductTabsHeader> headers = new ArrayList<>();
        StoreProductTabsHeader header1 = new StoreProductTabsHeader(0, "出售中商品", ProductStatusEnum.ON_SELLING.getIndex());
        StoreProductTabsHeader header2 = new StoreProductTabsHeader(0, "仓库中商品", ProductStatusEnum.NOT_SELLING.getIndex());
        StoreProductTabsHeader header3 = new StoreProductTabsHeader(0, "已经售馨商品", ProductStatusEnum.SOLD_OUT.getIndex());
        StoreProductTabsHeader header4 = new StoreProductTabsHeader(0, "警戒库存", ProductStatusEnum.STOCK_WARNING.getIndex());
        StoreProductTabsHeader header5 = new StoreProductTabsHeader(0, "商品回收站", ProductStatusEnum.DELETED.getIndex());
        headers.add(header1);
        headers.add(header2);
        headers.add(header3);
        headers.add(header4);
        headers.add(header5);
        for (StoreProductTabsHeader h : headers) {
            LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            ProductStatusEnum productStatusEnum = IndexEnum.valueOf(h.getType(), ProductStatusEnum.class);
            switch (productStatusEnum) {
                case ON_SELLING:
                    //出售中（已上架）
                    lambdaQueryWrapper.eq(StoreProduct::getIsShow, true);
                    lambdaQueryWrapper.eq(StoreProduct::getIsDel, false);
                    break;
                case NOT_SELLING:
                    //仓库中（未上架）
                    lambdaQueryWrapper.eq(StoreProduct::getIsShow, false);
                    lambdaQueryWrapper.eq(StoreProduct::getIsDel, false);
                    break;
                case SOLD_OUT:
                    //已售罄
                    lambdaQueryWrapper.le(StoreProduct::getStock, 0);
                    lambdaQueryWrapper.eq(StoreProduct::getIsDel, false);
                    break;
                case STOCK_WARNING:
                    //警戒库存
                    Integer stock = Integer.parseInt(systemConfigService.getValueByKey(Constants.SystemConfig.STORE_STOCK_WARNING));
                    lambdaQueryWrapper.le(StoreProduct::getStock, stock);
                    lambdaQueryWrapper.eq(StoreProduct::getIsDel, false);
                    break;
                case DELETED:
                    //回收站
                    lambdaQueryWrapper.or().eq(StoreProduct::getIsDel, true);
                    break;
                default:
                    break;
            }
            List<StoreProduct> storeProducts = dao.selectList(lambdaQueryWrapper);
            h.setCount(storeProducts.size());
        }

        return headers;
    }

    /**
     * 库存变动写入redis队列
     *
     * @param request StoreProductStockRequest 参数对象
     * @return int
     * @author Mr.Zhang
     * @since 2020-05-06
     */
    @Override
    public boolean stockAddRedis(StoreProductStockRequest request) {
        String productString = JSON.toJSONString(request);
        redis.getRedisTemplate().opsForList().leftPush(Constants.PRODUCT_STOCK_UPDATE, productString);
        return true;
    }

    /**
     * 后台任务批量操作库存
     */
    @Override
    public void consumeProductStock() {
        String redisKey = Constants.PRODUCT_STOCK_UPDATE;
        Long size = redis.getRedisTemplate().opsForList().size(redisKey);
        logger.info("StoreProductServiceImpl.doProductStock | size:" + size);
        if (size < 1) {
            return;
        }
        for (int i = 0; i < size; i++) {
            //如果10秒钟拿不到一个数据，那么退出循环
            Object data = redis.getRedisTemplate().opsForList().rightPop(redisKey, 10L, TimeUnit.SECONDS);
            if (null == data) {
                continue;
            }
            try {
                StoreProductStockRequest storeProductStockRequest =
                        JSON.toJavaObject(JSON.parseObject(data.toString()), StoreProductStockRequest.class);
                boolean result = doProductStock(storeProductStockRequest);
                if (!result) {
                    redis.getRedisTemplate().opsForList().leftPush(redisKey, data);
                }
            } catch (Exception e) {
                redis.getRedisTemplate().opsForList().leftPush(redisKey, data);
            }
        }
    }

    /**
     * 扣减库存添加销量
     *
     * @param productId 产品id
     * @param num       商品数量
     * @param type      是否限购
     * @return 扣减结果
     */
    @Override
    public boolean decProductStock(Integer productId, Integer num, Integer attrValueId, Integer type) {
        // 因为attrvalue表中unique使用Id代替，更新前先查询此表是否存在
        // 不存在=但属性 存在则是多属性
        StoreProductAttrValue productsInAttrValue =
                storeProductAttrValueService.getById(attrValueId);
        StoreProduct storeProduct = getById(productId);
        boolean result = false;
        if (null != productsInAttrValue) {
            result = storeProductAttrValueService.decProductAttrStock(productId, attrValueId, num, type);
        }
        LambdaUpdateWrapper<StoreProduct> lqwuper = new LambdaUpdateWrapper<>();
        lqwuper.eq(StoreProduct::getId, productId);
        lqwuper.set(StoreProduct::getStock, storeProduct.getStock() - num);
        lqwuper.set(StoreProduct::getSales, storeProduct.getSales() + num);
        result = update(lqwuper);
        if (result) { //判断库存警戒值
            Integer alterNumI = 0;
            String alterNum = systemConfigService.getValueByKey("store_stock");
            if (StringUtils.isNotBlank(alterNum)) alterNumI = Integer.parseInt(alterNum);
            if (alterNumI >= productsInAttrValue.getStock()) {
                // todo socket 发送库存警告
            }
        }
        return result;
    }

    /**
     * 根据商品id取出二级分类
     *
     * @param productIdsStr String 商品分类
     * @return {@code List<Integer>}
     */
    @Override
    public List<Integer> getSecondaryCategoryByProductId(String productIdsStr) {
        List<Integer> productIds = Strings.toIntListByComma(productIdsStr);
        if (Collections.isEmpty(productIds)) {
            return Collections.emptyList();
        }

        List<StoreProduct> products = dao.selectList(Wrappers.<StoreProduct>lambdaQuery().in(StoreProduct::getId, productIds));
        if (Collections.isEmpty(products)) {
            return Collections.emptyList();
        }

        Set<Integer> categoryIds = new HashSet<>();
        products.forEach(e -> categoryIds.addAll(Strings.toIntListByComma(e.getCateId())));

        if (Collections.isEmpty(categoryIds)) {
            return Collections.emptyList();
        }

        //取出所有的二级分类
        List<Category> categoryList = categoryService.getByIds(new ArrayList<>(categoryIds));
        if (Collections.isEmpty(categoryList)) {
            return Collections.emptyList();
        }

        return categoryList.stream()
                           .map(e -> {
                               List<Integer> parentIdList = Strings.toList(e.getPath(), "/", Integer::parseInt);
                               if (parentIdList.size() > 2) {
                                   Integer secondaryCategoryId = parentIdList.get(2);
                                   if (secondaryCategoryId > 0) {
                                       return secondaryCategoryId;
                                   }
                               }
                               return null;
                           }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 根据其他平台url导入产品信息
     *
     * @param url 待导入平台url
     * @param tag 1=淘宝，2=京东，3=苏宁，4=拼多多， 5=天猫
     * @return StoreProductReqBody
     */
    @Override
    public StoreProductReqBody importProductFromUrl(String url, int tag) {
        StoreProductReqBody productRequest = null;
        try {
            switch (tag) {
                case 1:
                    productRequest = productUtils.getTaobaoProductInfo(url, tag);
                    break;
                case 2:
                    productRequest = productUtils.getJDProductInfo(url, tag);
                    break;
                case 3:
                    productRequest = productUtils.getSuningProductInfo(url, tag);
                    break;
                case 4:
                    productRequest = productUtils.getPddProductInfo(url, tag);
                    break;
                case 5:
                    productRequest = productUtils.getTmallProductInfo(url, tag);
                    break;
                default:
                    throw new IllegalArgumentException();
            }
        } catch (Exception e) {
            throw new CrmebException("确认URL和平台是否正确，以及平台费用是否足额" + e.getMessage());
        }
        return productRequest;
    }


    /**
     * 推荐商品列表
     *
     * @param limit 最大数据量
     * @return 推荐商品列表集
     */
    @Override
    public List<StoreProduct> getRecommendStoreProduct(Integer limit) {
        Asserts.isTrue(limit > 0 && limit <= 20, () -> BizException.of("PRODUCT_RECOMMEND_NUM"));

        LambdaQueryWrapper<StoreProduct> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StoreProduct::getIsGood, 1);
        lambdaQueryWrapper.orderByDesc(StoreProduct::getSort).orderByDesc(StoreProduct::getId);
        return dao.selectList(lambdaQueryWrapper);
    }

    @Override
    public boolean deleteProduct(Integer productId, String type) {
        StoreProduct product = getById(productId);
        if (ObjectUtil.isNull(product)) {
            throw BizException.of(MessageConstants.PRODUCT_NOT_FOUND);
        }
        if (StrUtil.isNotBlank(type) && "recycle".equals(type) && Boolean.TRUE.equals(product.getIsDel())) {
            throw new CrmebException("商品已存在回收站");
        }

        LambdaUpdateWrapper<StoreProduct> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        if (StrUtil.isNotBlank(type) && "delete".equals(type)) {
            // 判断商品活动状态(秒杀、砍价、拼团)
            isExistActivity(productId);

            lambdaUpdateWrapper.eq(StoreProduct::getId, productId);
            int delete = dao.delete(lambdaUpdateWrapper);
            return delete > 0;
        }
        lambdaUpdateWrapper.eq(StoreProduct::getId, productId);
        lambdaUpdateWrapper.set(StoreProduct::getIsDel, true);
        return update(lambdaUpdateWrapper);
    }

    /**
     * 判断商品活动状态(秒杀、砍价、拼团)
     *
     * @param productId 商品id
     */
    private void isExistActivity(Integer productId) {
        boolean existActivity = storeSeckillService.isExistActivity(productId);
        if (existActivity) {
            throw new CrmebException("有商品关联的秒杀商品活动开启中，不能删除");
        }
        // 砍价活动判断
        existActivity = storeBargainService.isExistActivity(productId);
        if (existActivity) {
            throw new CrmebException("有商品关联的砍价商品活动开启中，不能删除");
        }
        // 拼团活动判断
        existActivity = storeCombinationService.isExistActivity(productId);
        if (existActivity) {
            throw new CrmebException("有商品关联的拼团商品活动开启中，不能删除");
        }
    }

    /**
     * 恢复已删除的商品
     *
     * @param productId 商品id
     * @return 恢复结果
     */
    @Override
    public boolean reStoreProduct(Integer productId) {
        LambdaUpdateWrapper<StoreProduct> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(StoreProduct::getId, productId);
        lambdaUpdateWrapper.set(StoreProduct::getIsDel, false);
        return update(lambdaUpdateWrapper);
    }

    ///////////////////////////////////////////自定义方法

    /**
     * 扣减库存任务操作
     *
     * @param storeProductStockRequest 扣减库存参数
     * @return 执行结果
     */
    @Override
    public boolean doProductStock(StoreProductStockRequest storeProductStockRequest) {
        // 获取商品本身信息
        StoreProduct existProduct = getById(storeProductStockRequest.getProductId());
        List<StoreProductAttrValue> existAttr =
                storeProductAttrValueService.getListByProductIdAndAttrId(
                        storeProductStockRequest.getProductId(),
                        storeProductStockRequest.getAttrId().toString(),
                        storeProductStockRequest.getType());
        if (null == existProduct || null == existAttr) { // 未找到商品
            logger.info("库存修改任务未获取到商品信息" + JSON.toJSONString(storeProductStockRequest));
            return true;
        }

        // 回滚商品库存/销量 并更新
        boolean isPlus = storeProductStockRequest.getOperationType().equals("add");
        int productStock = isPlus ? existProduct.getStock() + storeProductStockRequest.getNum() : existProduct.getStock() - storeProductStockRequest.getNum();
        existProduct.setStock(productStock);
        existProduct.setSales(existProduct.getSales() - storeProductStockRequest.getNum());
        updateById(existProduct);

        // 回滚sku库存
        for (StoreProductAttrValue attrValue : existAttr) {
            int productAttrStock = isPlus ? attrValue.getStock() + storeProductStockRequest.getNum() : attrValue.getStock() - storeProductStockRequest.getNum();
            attrValue.setStock(productAttrStock);
            attrValue.setSales(attrValue.getSales() - storeProductStockRequest.getNum());
            storeProductAttrValueService.updateById(attrValue);
        }
        return true;
    }

    /**
     * 获取复制商品配置.copyNum 复制条数(一号通类型下有值)
     *
     * @return copyType 复制类型：1：一号通
     */
    @Override
    public MyRecord copyConfig() {
        String copyType = systemConfigService.getValueByKey("system_product_copy_type");
        if (StrUtil.isBlank(copyType)) {
            throw new CrmebException("请先进行采集商品配置");
        }
        int copyNum = 0;
        if (copyType.equals("1")) {
            JSONObject info = onePassService.info();
            copyNum = Optional.ofNullable(info.getJSONObject("copy").getInteger("surp")).orElse(0);
        }
        MyRecord record = new MyRecord();
        record.set("copyType", copyType);
        record.set("copyNum", copyNum);
        return record;
    }

    /**
     * 复制平台商品
     *
     * @param url 商品链接
     * @return MyRecord
     */
    @Override
    public MyRecord copyProduct(String url) {
        JSONObject jsonObject = onePassService.copyGoods(url);
        StoreProductReqBody storeProductReqBody = ProductUtils.onePassCopyTransition(jsonObject);
        MyRecord record = new MyRecord();
        return record.set("info", storeProductReqBody);
    }

}

